package com.diorsunion.hedge.quota;

import com.diorsunion.hedge.dal.entity.stock.Stock;
import com.diorsunion.hedge.dal.entity.stock.StockPrice;
import com.diorsunion.hedge.util.CollectionTools;
import com.diorsunion.hedge.util.MathUtils;
import com.google.common.collect.Lists;
import org.springframework.util.CollectionUtils;

import java.util.List;

/*************
 * KDJ指标计算
 * KDJ公式：
 * RSV=(Cn-Ln)/(Hn-Ln)* 100
 * K = RSV(t)/m1 + (m1-1)*K(t-1)/m1
 * D = K(t)/m2   + (m2-1)*D(t-1)/m2
 * J = 3*D - 2*K
 * 其中
 * Cn:第n日的收盘价格
 * Ln:n日内最低收盘价格
 * Hn:n日内最高收盘价格
 * 在代码中
 * n = 9
 * m1 = 3
 * m2 = 3
 * Created by harley-dog on 2016/5/3.
 */
public class KDJFilter implements StockPriceExFilter {
    final int n,m1,m2;
    public KDJFilter(int n,int m1,int m2){
        this.n = n;
        this.m1 = m1;
        this.m2 = m2;
    }

    @Override
    public void filter(Stock stock, List<StockPrice> lastList, List<StockPrice> stockPriceList) {
        int lastSize = CollectionUtils.isEmpty(lastList)?0:lastList.size();
        for(int i=0;stockPriceList!=null && i<stockPriceList.size();i++){
            StockPrice stockPrice = stockPriceList.get(i);
            double last_k = 50;
            double last_d = 50;
            if(i==0 && !CollectionUtils.isEmpty(lastList)){
                last_k = lastList.get(lastSize-1).ex.k;
                last_d = lastList.get(lastSize-1).ex.d;
            }else if(i>0){
                last_k = stockPriceList.get(i-1).ex.k;
                last_d = stockPriceList.get(i-1).ex.d;
            }

            double cn = stockPrice.close;
            //首先得取N日最低和N日最高
            //第一步要计算i-9 到 i 这九天内的最高
            List<Double> closes = Lists.newArrayList();
            if(i>=n-1){
                //说明九天都在stockPriceList里
                for(int m=i-(n-1);m<=i;m++){
                    StockPrice s = stockPriceList.get(m);
                    closes.add(s.close);
                }
            }else{
                //说明(i)天的值在stockPriceList里,(9-i)天的值在lastList里
                for(int m=0;m<=i;m++){
                    StockPrice s = stockPriceList.get(m);
                    closes.add(s.close);
                }

                //假设 i= 6,说明在stockPriceList取0-6 = 7天,在lastList里(9-7)=2天，从 lastSize-1取到lastSize-1-2
                int c = n-1-i;//剩余要补充的天数
                //接下来循环有两个条件，1: 不能超过lastList的个数,2:不能超过c剩余个数
                for(int m=lastSize-1,h=0 ;m>=0 && h<c ;m--,h++){
                    StockPrice s = lastList.get(m);
                    closes.add(s.close);
                }
            }
            double[] a = CollectionTools.toDoubleArray(closes);
            double[] maxmin = MathUtils.getMaxMin(a);
            double rsv = maxmin[0]==maxmin[1]?0:(cn-maxmin[1])/(maxmin[0]-maxmin[1])*100;
            double k = last_k*(m1-1)/m1 + rsv/m1;
            double d = last_d*(m2-1)/m2 + k/m2;
            double j = k*3 - d*2;
            stockPrice.ex.k = k;
            stockPrice.ex.d = d;
            stockPrice.ex.j = j;
        }
    }
}
